package com.llm.travel_agent_assistant.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.llm.travel_agent_assistant.dto.BudgetAnalyzeDTO;
import com.llm.travel_agent_assistant.dto.GeneratePlanDTO;
import com.llm.travel_agent_assistant.dto.QuestionDTO;
import com.llm.travel_agent_assistant.dto.Result;
import com.llm.travel_agent_assistant.entity.BudgetAnalyze;
import com.llm.travel_agent_assistant.entity.TravelPlan;
import com.llm.travel_agent_assistant.mapper.BudgetAnalyzeMapper;
import com.llm.travel_agent_assistant.mapper.TravelPlanMapper;
import com.llm.travel_agent_assistant.service.OpenAiService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import opennlp.tools.util.StringUtil;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import javax.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
public class OpenAiServiceImpl implements OpenAiService {

    @Resource
    @Qualifier("deepSeekClient")
    private ChatClient chatClient;
    @Resource
    private TravelPlanMapper travelPlanMapper;
    @Resource
    private BudgetAnalyzeMapper budgetAnalyzeMapper;

    @Override
    public Result generateTravelPlan(GeneratePlanDTO generatePlanDTO) {
        String systemPrompt = String.format("""
                **前提**: 你是资深导游，精通全球景点，擅长结合用户需求制定精准旅行计划，熟悉交通、住宿、餐饮定价及景点细节。
                
                **当前用户需求**: %s
                
                **需求处理规则**:
                1. 若内容与旅游无关，仅返回[NOT_TRAVEL_RELEVANT_QUESTION]，无其他信息
                2. 提取核心信息：目的地、日期（默认3天）、预算、人数（默认2人）、偏好（自然风光/人文等，无则均衡）
                3. 总结目的地亮点（约200字）：含标志性景点、文化特色、必尝美食
                
                **旅行计划要素**:
                - 交通：往返及市内方式，单人/总计费用，耗时说明
                - 住宿：2-3家高性价比酒店，含名称、位置、房型、每晚人均/总计费用
                - 景点：每日2-3个核心景点，标注位置、时长、门票（按人数计）、交通方式
                - 餐厅：每日1-2家特色餐厅，含名称、位置、招牌菜，按人数计人均/总计费用
                - 预算适配：确保总费用不超用户预算，超支则调整（替换住宿/选免费景点等）
                
                **输出格式**:
                旅行计划名称: [目的地_天数_核心主题旅行计划]
                目的地亮点总结: [约200字核心亮点]
                行程规划:
                DAY1:
                - 时间：[时间段]
                  景点：[名称+位置]
                  交通：[方式+费用（总计）]
                  花费：[门票+交通合计]
                  备注：[游玩贴士]
                - 时间：[时间段]
                  餐厅：[名称+位置+招牌菜]
                  花费：[总计餐费]
                - 晚间安排：[如逛夜市/休息]
                DAY2: [格式同DAY1]
                DAYn: [含返程交通]
                住宿推荐:
                1. 酒店名称：[全称]
                   位置：[区域+交通]
                   房型：[如标准间]
                   费用：[每晚总计+人均]
                   推荐理由：[近景点/性价比高等]
                2. [第二家酒店]
                餐厅汇总:
                1. 餐厅名称：[全称]
                   位置：[地址/区域]
                   招牌菜：[1-2道]
                   人均费用：[金额]
                2. [后续餐厅]
                预算总结:
                - 总费用：[交通+住宿+景点+餐饮，总计]
                - 预算适配说明：[如“符合XXX元预算”或“调整后未超支”]
                
                **注意**: 严格按上述格式输出，无多余信息
                """, generatePlanDTO.getMessage());
        String travelPlan = chatClient.prompt(systemPrompt).call().content();

        // 如果不是旅游相关问题，直接返回
        if (travelPlan != null && travelPlan.contains("NOT_TRAVEL_RELEVANT_QUESTION")) {
            return Result.fail("我只是一名旅行助手，很抱歉无法回答其他问题");
        }
        // 把解析后的计划存到数据库
        String parsedTravelPlan = parseTravelPlan(travelPlan);
        String planName = getPlanName(parsedTravelPlan);

        // 去掉计划名称的中括号
        parsedTravelPlan = parsedTravelPlan.replace("[", "");
        parsedTravelPlan = parsedTravelPlan.replace("]", "");

        TravelPlan plan = new TravelPlan();
        plan.setPlanId(RandomUtil.randomNumbers(20));
        plan.setPlanName(planName);
        plan.setPlanContent(parsedTravelPlan);
        plan.setCreateTime(LocalDateTime.now());
        plan.setOwnerId(generatePlanDTO.getOwnerId());
        travelPlanMapper.insert(plan);
        // 直接返回 ok 让用户去计划列表查看最新计划
        return Result.ok();
    }

    @Override
    public Result budgetAnalyze(BudgetAnalyzeDTO budgetAnalyzeDTO) {
        String systemPrompt = String.format("""
                **前提**: 你是资深导游，熟悉全球旅游目的地及消费标准，擅长结合行程细节精准核算费用，能清晰呈现各项开支明细。
                
                **当前用户需求**: %s
                
                **分析与处理规则**:
                1. 若内容与旅游无关，仅返回标识 [NOT_BUDGET_ANALYZE_QUESTION]，无其他信息
                2. 提取核心信息：旅行目的地、出行天数、预算范围、同行人数、旅行偏好（如经济型/舒适型）
                3. 基于目的地特点，规划合理行程（含交通、住宿、景点、餐饮），并细化每项费用
                4. 费用计算需结合人数和天数，确保数据真实合理（参考当地实时消费标准）
                
                **预算明细要求**:
                - 交通：区分大交通（如航班/高铁）和市内交通（如地铁/打车），标注单程/往返、人均及总计
                - 住宿：明确酒店名称、位置（如商圈/景点附近）、房型、每晚价格及总费用
                - 景点：列出核心景点名称，标注门票单价、按人数计算的总费用
                - 餐饮：推荐当地特色餐厅，标注人均消费、按人数和天数计算的总费用
                
                **输出格式**:
                费用预算分析名称: [旅行目的地_费用预算分析]
                预算明细:
                    ~ 交通:
                        - 大交通: [如：北京-上海高铁二等座]，¥550/人x2人（往返），总计¥2200
                        - 市内交通: [如：地铁3日票+打车2次]，¥80/人+¥150，总计¥310
                    ~ 住宿:
                        - [如：上海外滩华尔道夫酒店]（外滩附近，豪华大床房），¥1200/晚x2晚，总计¥2400
                    ~ 景点:
                        - [如：上海迪士尼乐园]（门票），¥599/人x2人，总计¥1198
                        - [如：外滩观光隧道]，¥50/人x2人，总计¥100
                    ~ 餐饮:
                        - [如：南翔小笼包（豫园店）]，¥80/人x2人（午餐），总计¥160
                        - [如：上海本帮菜餐厅]，¥150/人x2人（晚餐），总计¥300
                预算总费用: ¥2200(交通)+¥2400(住宿)+¥1298(景点)+¥460(餐饮)=¥6358
                
                **注意**: 严格按上述格式输出，每项费用需具体可查，不添加额外说明
                """, budgetAnalyzeDTO.getMessage());
        String budgetAnalyze = chatClient.prompt(systemPrompt).call().content();
        if (budgetAnalyze != null && budgetAnalyze.contains("NOT_BUDGET_ANALYZE_QUESTION")) {
            return Result.fail("我只是一名预算分析助手，很抱歉无法回答其他问题");
        }

        String parseBudgetAnalyze = parseBudgetAnalyze(budgetAnalyze);
        String budgetAnalyzeName = getPlanName(parseBudgetAnalyze);

        // 去掉名称的中括号
        parseBudgetAnalyze = parseBudgetAnalyze.replace("[", "");
        parseBudgetAnalyze = parseBudgetAnalyze.replace("]", "");

        // 保存
        BudgetAnalyze analyze = new BudgetAnalyze();
        analyze.setAnalyzeId(RandomUtil.randomNumbers(20));
        analyze.setAnalyzeName(budgetAnalyzeName);
        analyze.setCreateTime(LocalDateTime.now());
        analyze.setAnalyzeContent(parseBudgetAnalyze);
        analyze.setOwnerId(budgetAnalyzeDTO.getUserId());
        budgetAnalyzeMapper.insert(analyze);
        // 直接返回 ok 让用户去预算分析列表查看最新分析
        return Result.ok();
    }

    @Override
    public Result solveAnyQuestion(QuestionDTO questionDTO) {
        String systemPrompt = String.format("""
                **前提:** 你是一个万能的生活小助手，对于旅游、安全(比如遇到危险该怎么处理)、地理(熟悉世界各国的城市、地理信息)特别的擅长
                
                ** 当前用户需求: ** %s
                **分析用户需求:**
                    1.深度理解用户的需求，对需求进行细致的分析
                    2.根据用户表达需求，以及你的分析，给出合理的解决方案
                ** 输出格式: **
                    需求分析: 对用户需求的细致分析
                    解决方案: 在分析阶段你所给出的解决方案，可以分点列出
                ** 注意: **
                    输出要求严格按照输出格式来
                """, questionDTO.getQuestion());

        String content = chatClient.prompt(systemPrompt).call().content();
        return Result.ok(parseAnyQuestion(content));
    }

    private String parseAnyQuestion(String content) {
        log.info("content: {}", content);
        String[] split = content.split("\n");

        StringBuilder sectionContent = new StringBuilder();

        for (String line : split) {
            line = line.replace("###", "");
            line = line.replace("**", "");
            line = line.trim();
            if (StringUtil.isEmpty(line)) {
            } else if (line.contains("需求分析")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("解决方案")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            }
        }
        return sectionContent.toString();
    }

    private String parseBudgetAnalyze(String budgetAnalyze) {
        log.info("parseBudgetAnalyze: {}", budgetAnalyze);
        String[] split = budgetAnalyze.split("\n");

        StringBuilder sectionContent = new StringBuilder();

        for (String line : split) {
            line = line.replace("###", "");
            line = line.replace("**", "");
            line = line.trim();
            if (StringUtil.isEmpty(line)) {
            } else if (line.contains("费用预算分析名称")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("预算明细")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("预算总费用")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            }
        }
        return sectionContent.toString();
    }

    private String parseTravelPlan(String travelPlan){
        log.info("parseTravelPlan: {}", travelPlan);
        String[] split = travelPlan.split("\n");

        StringBuilder sectionContent = new StringBuilder();

        for (String line : split) {
            line = line.replace("###", "");
            line = line.replace("**", "");
            line = line.trim();
            if (StringUtil.isEmpty(line)) {
            } else if (line.contains("旅行计划名称")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("旅行目的地相关景点")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("交通方式")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("住宿")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else if (line.contains("餐厅")) {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            } else {
                sectionContent.append(line);
                sectionContent.append("<br/><br/>");
            }
        }
        return sectionContent.toString().trim();
    }

    public String getPlanName(String str) {
        // 正则匹配：找出第一个 [ ... ] 中的内容
        Pattern pattern = Pattern.compile("\\[(.*?)\\]");
        Matcher matcher = pattern.matcher(str);

        if (matcher.find()) {
            return matcher.group(1); // group(1) 是 [] 中的内容
        } else {
            return ""; // 或者抛异常
        }
    }
}
